﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Compression;
using System.Data;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;

namespace Utilities.Data
{
    public class DataCompression
    {
        //缓冲大小
        private const int BUFFER_SIZE = 4096;

        // 对称密钥 需要变更
        // private static byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
        //    7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2
        //};
        //向量
        // private static byte[] IV = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };


        #region DataSet 压缩 解压

        public static byte[] CompressDataSet(DataSet ds)
        {
            ds.RemotingFormat = SerializationFormat.Binary;
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            MemoryStream objStream = new MemoryStream();
            DeflateStream zipStream = null;
            try
            {
                bf.Serialize(ms, ds); //使用二进制序列化DataSet到流中
                byte[] inbyt = ms.ToArray();

                zipStream = new DeflateStream(objStream, CompressionMode.Compress);
                zipStream.Write(inbyt, 0, inbyt.Length);
            }
            catch
            {
                throw;
            }
            finally
            {
                zipStream.Close();
                ms.Close();
                objStream.Close();
            }
            return objStream.ToArray();
        }


        public static byte[] CompressDataTable(DataTable data)
        {
            data.RemotingFormat = SerializationFormat.Binary;
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            MemoryStream objStream = new MemoryStream();
            DeflateStream zipStream = null;
            try
            {
                bf.Serialize(ms, data); //使用二进制序列化DataSet到流中
                byte[] inbyt = ms.ToArray();

                zipStream = new DeflateStream(objStream, CompressionMode.Compress);
                zipStream.Write(inbyt, 0, inbyt.Length);
            }
            catch
            {
                throw;
            }
            finally
            {
                zipStream.Close();
                ms.Close();
                objStream.Close();
            }
            return objStream.ToArray();

        }


        public static DataSet DecompressDataSet(byte[] bytDs)
        {
            DataSet outDs = new DataSet();
            MemoryStream inMs = new MemoryStream(bytDs);
            inMs.Seek(0, 0);
            using (DeflateStream zipStream = new DeflateStream(inMs, CompressionMode.Decompress, true))
            {
                byte[] outByt = ReadFullStream(zipStream);
                zipStream.Flush();
                zipStream.Close();
                MemoryStream outMs = new MemoryStream(outByt);
                outMs.Seek(0, 0);
                outDs.RemotingFormat = SerializationFormat.Binary;
                BinaryFormatter bf = new BinaryFormatter();
                outDs = (DataSet)bf.Deserialize(outMs, null);
            }
            return outDs;
        }

        public static DataTable DecompressDataTable(byte[] bytDs)
        {
            DataTable data = new DataTable();
            MemoryStream inMs = new MemoryStream(bytDs);
            inMs.Seek(0, 0);
            using (DeflateStream zipStream = new DeflateStream(inMs, CompressionMode.Decompress, true))
            {
                byte[] outByt = ReadFullStream(zipStream);
                zipStream.Flush();
                zipStream.Close();
                MemoryStream outMs = new MemoryStream(outByt);
                outMs.Seek(0, 0);
                data.RemotingFormat = SerializationFormat.Binary;
                BinaryFormatter bf = new BinaryFormatter();
                data = (DataTable)bf.Deserialize(outMs, null);
            }
            return data;
        }
        #endregion


        #region 常用方法
        public static byte[] ReadFullStream(Stream stream)
        {
            using (MemoryStream ms = GetReadMemoryStream(stream))
            {
                return ms.ToArray();
            }
        }

        public static MemoryStream GetReadMemoryStream(Stream stream)
        {
            MemoryStream ms = new MemoryStream();
            ReadAndWriteStream(stream, ms);
            return ms;
        }


        #region 读取 并写入到流中
        public static void ReadAndWriteStream(Stream readStream, Stream writeStream)
        {
            byte[] buffer = new byte[BUFFER_SIZE];

            while (true)
            {
                int read = readStream.Read(buffer, 0, buffer.Length);
                if (read <= 0)
                    break;
                writeStream.Write(buffer, 0, read);
            }
        }

        #endregion

        #endregion


        #region 压缩流 解压缩流
        public static byte[] Compress(Stream stream)
        {
            MemoryStream ms = new MemoryStream();
            DeflateStream zipStream = new DeflateStream(ms, CompressionMode.Compress);

            try
            {
                ReadAndWriteStream(stream, zipStream);
            }
            catch
            {
                throw;
            }
            finally
            {
                zipStream.Close();//必须先关闭
                ms.Close();
            }
            return ms.ToArray();
        }


        /// <summary>
        /// 压缩流
        /// </summary>
        /// <param name="stream">流</param>
        /// <returns>字节</returns>
        public static byte[] Decompress(Stream stream)
        {
            MemoryStream ms = new MemoryStream();
            DeflateStream zipStream = new DeflateStream(stream, CompressionMode.Decompress);
            try
            {
                ReadAndWriteStream(zipStream, ms);
            }
            catch
            {
                throw;
            }
            finally
            {
                ms.Close();
                zipStream.Close();
            }
            return ms.ToArray();
        }
        #endregion


        #region 压缩 加密 解密
        /// <summary>
        /// 将对象压缩加密到字节数据
        /// </summary>
        /// <param name="obj">要压缩加密的对象</param>
        /// <returns>处理后生成的字节数组</returns>
        public static byte[] CompressEncryptToBytes(object obj, byte[] key, byte[] IV)
        {
            // 建立对称密码信息
            MemoryStream ms = new MemoryStream();
            RijndaelManaged rm = new RijndaelManaged();
            CryptoStream enCrpStrm = new CryptoStream(ms, rm.CreateEncryptor(key, IV), CryptoStreamMode.Write);

            DeflateStream zip = new DeflateStream(enCrpStrm, CompressionMode.Compress, true);
            try
            {
                BinaryFormatter serializer = new BinaryFormatter();
                serializer.Serialize(zip, obj);
                zip.Close();                    // 在返回（return）这前一定要进行关闭
                enCrpStrm.FlushFinalBlock();    // 在返回（return）这前一定要进行调用。
                return ms.ToArray();
            }
            catch
            {
                throw;
            }
            finally
            {
                enCrpStrm.Close();
                ms.Close();
            }
        }

        /// <summary>
        /// 将字节数组进行解密解压还原成对象
        /// </summary>
        /// <param name="ary">要处理的字节数组</param>
        /// <returns>被还原的对象</returns>
        public static object DecompressDecryptToObject(byte[] ary, byte[] key, byte[] IV)
        {
            MemoryStream ms = new MemoryStream(ary);
            RijndaelManaged rm = new RijndaelManaged();
            CryptoStream deCrpStrm = new CryptoStream(ms, rm.CreateDecryptor(key, IV), CryptoStreamMode.Read);
            DeflateStream UnZip = new DeflateStream(deCrpStrm, CompressionMode.Decompress);
            try
            {
                BinaryFormatter serializer = new BinaryFormatter();
                return serializer.Deserialize(UnZip);
            }
            catch { throw; }
            finally
            {
                UnZip.Close();
                deCrpStrm.Close();
                ms.Close();
            }
        }

        /// <summary>
        /// 将对象压缩到字节数组
        /// </summary>
        /// <param name="obj">要压缩的对象</param>
        /// <returns>压缩后的字节数组</returns>
        public static byte[] CompressedToBytes(object obj)
        {
            MemoryStream ms = new MemoryStream();
            DeflateStream zip = new DeflateStream(ms, CompressionMode.Compress, true);
            try
            {
                BinaryFormatter serializer = new BinaryFormatter();
                serializer.Serialize(zip, obj);
            }
            catch
            {
                throw;
            }
            finally
            {
                ms.Close();
                zip.Close();
            }
            return ms.ToArray();
        }

        /// <summary>
        /// 解压缩后对象
        /// </summary>
        /// <param name="ary">字节数组</param>
        /// <returns>对象</returns>
        public static object DecompressToObject(byte[] ary)
        {
            MemoryStream ms = new MemoryStream(ary);
            DeflateStream UnZip = new DeflateStream(ms, CompressionMode.Decompress);
            object obj;
            try
            {
                BinaryFormatter serializer = new BinaryFormatter();
                obj = serializer.Deserialize(UnZip);
            }
            catch
            {
                throw;
            }
            finally
            {
                ms.Close();
                UnZip.Close();
            }
            return obj;
        }
        #endregion
    }
}
